#include"StdAfx.h"

int IEventListener::numInstances = 0;

pgEventManager::pgEventManager()
{
}
pgEventManager::~pgEventManager()
{
}

void pgEventManager::RegisterListener(IEventListener* listener, int eventClass, int eventName)
{
	if(listener)
	{
#ifdef _DEBUG
		_CrtCheckMemory();
#endif
		SListenerEx *exListener = new NEW_MEM_LEAK SListenerEx;

		exListener->registeredClass = eventClass;
		exListener->registeredEvent = eventName;
		exListener->registeredObject = listener;

#ifdef DEBUG_EVENT_MANAGER
		g_PG_pLog->fTextout(GREEN, false, "Registered listener id : %d\n, eventName :%d, eventClass, %d", exListener->registeredObject->id, eventName, eventClass);
#endif

		extendedRegister.push_back(exListener);	
	}
}

void pgEventManager::UnregisterListener(IEventListener* listener)
{
	// TODO 
	// Theres something screwy going on when trying to unregister a not registered listener...
	std::list<SListenerEx*>::iterator itEx;
	std::list<SListenerEx*>::iterator itDel;
	bool bFound = false;

	if(listener)
	{
		for (itEx = extendedRegister.begin(); itEx != extendedRegister.end(); itEx++)
		{
			if((*itEx)->registeredObject->id == listener->id)
			{
				itDel = itEx;
				bFound = true;
				break;
			}
		}	
	}

	// POSSIBLE FAIL
	// This might lead to access violations if an object is thought to live on after 
	// unregistering.
	if (bFound == true)
	{
		delete(*itDel);
		extendedRegister.remove(*itDel);
	}
	else
		PG_LOG_WARNING_EX(TOPIC_PGEVENT_MANAGER, "Trying to unregister a non registered listener");
}

void pgEventManager::RegisterEvent(int eventName = E_UNKNOWN, int eventClass = EC_UNKNOWN, IEventData *pData = NULL)
{

	if (eventName == E_ONCRITICAL_ERROR)
	{
		FireCriticalErrorEvent();
		return;
	}

#ifdef _DEBUG
	_CrtCheckMemory();
#endif
	// --
	IEvent *eEvent = new NEW_MEM_LEAK IEvent;

	eEvent->eventClass = eventClass;
	eEvent->eventId	= eventName;
	eEvent->pData = pData;

#ifdef DEBUG_EVENT_MANAGER
	g_PG_pLog->fTextout(GREEN, "Created event with id %d class %d, orig id %d class %d\n", eEvent->eventId, eEvent->eventClass, eventName, eventClass);
#endif
	eventQueue.push_back(eEvent);
}


void pgEventManager::FireEvents()
{
	std::list<SListenerEx*>::iterator it = extendedRegister.begin() ;
	std::list<IEvent*>::iterator itEvent = eventQueue.begin();


	while (it != extendedRegister.end())
	{	
		while (itEvent != eventQueue.end())
		{
#ifdef DEBUG_EVENT_MANAGER

			if(((*itEvent)->eventId == (*it)->registeredEvent) && ((*itEvent)->eventClass == (*it)->registeredClass))
				PG_LOG_INFO("Register very specific fired");

			if((((*it)->registeredClass == EC_UNKNOWN) && ((*it)->registeredEvent == E_UNKNOWN)))
				PG_LOG_INFO("Register for all fired");

			if((((*itEvent)->eventClass == (*it)->registeredClass) && ((*it)->registeredEvent == E_UNKNOWN)))
				PG_LOG_INFO("Register for all events in class fired");
#endif		

			if(
				(((*itEvent)->eventId == (*it)->registeredEvent) && ((*itEvent)->eventClass == (*it)->registeredClass)) // either it registered for a specific event and class
				||
				(((*it)->registeredClass == EC_UNKNOWN) && ((*it)->registeredEvent == E_UNKNOWN)) // or for all events and all classes
				||
				(((*itEvent)->eventClass == (*it)->registeredClass) && ((*it)->registeredEvent == E_UNKNOWN)) // for all events of a specific class
				)
			{
				// fire them off
				(*it)->registeredObject->OnEvent(*itEvent);		
			}
			itEvent++;
		}

		itEvent =  eventQueue.begin();	
		it++;
	} 

	// Stupid circular referencing makes (look) programmer dumb
	// Stupid circular referencing makes (look) programmer dumb
	// Stupid circular referencing makes (look) programmer dumb
	// Stupid circular referencing makes (look) programmer dumb
	for (itEvent = eventQueue.begin(); itEvent != eventQueue.end(); ++itEvent)
	{
		delete (*itEvent);
	}
	eventQueue.clear();
}

void pgEventManager::Update(float frameTime)
{
	FireEvents();
}

void pgEventManager::ShutDown()
{
	std::list<IEvent*>::iterator itEvent;
	std::list<SListenerEx*>::iterator itListener;

	// clear all events
	for (itEvent = eventQueue.begin(); itEvent != eventQueue.end(); itEvent++)
	{
		delete (*itEvent);
		(*itEvent) = NULL;
	}

	//clear all listeners
	for (itListener = extendedRegister.begin(); itListener != extendedRegister.end(); itListener++)
	{
		delete (*itListener);
		(*itListener) = NULL;
	}

	// clear all error listeners
	std::list<IEventListener*>::iterator itErrorListeners;
	std::list<IEventListener*>::iterator itErrorListenersEnd;

	itErrorListenersEnd = errorListeners.end();

	
}

void pgEventManager::FireCriticalErrorEvent()
{
	std::list<IEventListener*>::iterator itErr = errorListeners.begin();
	std::list<SListenerEx*>::iterator it = extendedRegister.begin();

	IEvent *errorEvent = new NEW_MEM_LEAK IEvent;
	errorEvent->eventId = E_ONCRITICAL_ERROR;

	while (it != extendedRegister.end())
	{
		(*it)->registeredObject->OnEvent(errorEvent);
		++it;
	}

	while (itErr != errorListeners.end())
	{
		(*itErr)->OnEvent(errorEvent);
		++itErr;
	}

	if (errorEvent)
		delete errorEvent;
}

void pgEventManager::RegisterCriticalErrorListener(IEventListener *pListener)
{
	if (pListener)
	{
		errorListeners.push_back(pListener);
	}
}

void pgEventManager::UnregisterCriticalErrorListener(IEventListener *pListener)
{

	// TODO 
	// Theres something screwy going on when trying to unregister a not registered listener...
	std::list<IEventListener*>::iterator itEx;
	std::list<IEventListener*>::iterator itDel;
	bool bFound = false;

	if(pListener)
	{
		for (itEx = errorListeners.begin(); itEx != errorListeners.end(); ++itEx)
		{
			if((*itEx)->id == pListener->id)
			{
				itDel = itEx;
				bFound = true;
				break;
			}
		}	
	}

	// POSSIBLE FAIL
	// This might lead to access violations if an object is thought to live on after 
	// unregistering.
	if (bFound == true)
	{
//		delete (*itDel);
		errorListeners.remove(*itDel);	
	}
	else
		PG_LOG_WARNING_EX(TOPIC_PGEVENT_MANAGER, "Trying to unregister a non registered listener");
}